

#include "gen_sync_serial_trms.h"


/****** General synchronous serial transmission *******/

/***********************************************
General synchronous serial transmission

Master: The object that sends the sync clock signal
Slave: The object that receives the sync clock signal

LSB: Last/Least Significant Bit (bit0/right bit) first send
MSB: Most Significant Bit (bit7/lift bit) first send

CPOL / CKP: Clock Polarity
CPOL = 0: clock idle state is low level
CPOL = 1: clock idle state is high level

CPHA / CKE: Clock Phase / Clock Edge
CPHA = 0: Data is clocked on the leading edge 
	For CPOL = 0, this is the rising edge
	For CPOL = 1, this is the falling edge
CPHA = 1: Data is clocked on the trailing edge 
	For CPOL = 0, this is the falling edge
	For CPOL = 1, this is the rising edge

CPHA == CPOL, Data is clocked on rising edge
CPHA != CPOL, Data is clocked on falling edge

If the master is write data to slave，
the clock edge that the data signal remains unchanged is data locked edge
If the master is read data from slave，
the clock edge that the data signal changed is data prepare edge
and the other edge is data locked edge

e.g.
I2C:
	gsst_i2c_master.config.mst_slv = 0;			//mater
	gsst_i2c_master.config.lsb_msb = 1;			//MSB
	gsst_i2c_master.config.cpol = 0;			//clock idle state is low level
	gsst_i2c_master.config.cpha = 0;			//data is clocked on the rising edge, and cpol = 0, so cpha = cpol = 0
	gsst_i2c_master.bpt = 8;

74HC595:
	gsst_74hc595_master.config.mst_slv = 0;	 	//mater
	gsst_74hc595_master.config.lsb_msb = 1;	 	//MSB
	gsst_74hc595_master.config.cpol = 0;		//clock idle state is low level
	gsst_74hc595_master.config.cpha = 0;		//data is clocked on the rising edge, and cpol = 0, so 0 == cpha == cpol
	gsst_74hc595_master.bpt = 8;	

74HC165:
	gsst_74hc165_master.config.mst_slv = 0;	 	//mater
	gsst_74hc165_master.config.lsb_msb = 1;	 	//MSB
	gsst_74hc165_master.config.cpol = 1;		//clock idle state is high level
	gsst_74hc165_master.config.cpha = 0;		//data is clocked on the falling edge, and cpol = 1, so 0 == cpha != cpol
	gsst_74hc165_master.bpt = 8;

HT1621:
	gsst_ht1621_master.config.mst_slv = 0;	 	//mater
	gsst_ht1621_master.config.lsb_msb = 0;	 	//LSB
	gsst_ht1621_master.config.cpol = 1;			//clock idle state is high level
	gsst_ht1621_master.config.cpha = 1;			//data is clocked on the rising edge, and cpol = 1, so 1 == cpha == cpol
	gsst_ht1621_master.bpt = n;					//in this case, the bit per transfer will change

DAC8562:
	gsst_dac8562_master.config.mst_slv = 0;	 	//mater
	gsst_dac8562_master.config.lsb_msb = 1;	 	//MSB
	gsst_dac8562_master.config.cpol = 0;		//clock idle state is low level
	gsst_dac8562_master.config.cpha = 1;		//data is clocked on the falling edge, and cpol = 0, so 1 == cpha != cpol
	gsst_dac8562_master.bpt = 23;

***********************************************/

U32 gsst_transmit_master(GSST_STRUCT* gsst, U32 send_data)
{
	U8 i;
	U8 bit;
	U32 mark;
	U32 rec = 0;

	if(gsst->config.mst_slv != 0){
		return 0;
	}
	if(gsst->bpt > 32){
		return 0;
	}
	if(gsst->delay == 0){
		return 0;
	}
	if(gsst->clk_set == 0){
		return 0;
	}

	if(gsst->config.lsb_msb){
		mark = 1<<(gsst->bpt-1);
	}
	else{
		mark = 1;
	}

	//clock idle state
	gsst->clk_set(gsst->config.cpol);
	//CPHA = 1, send the leading edge
	if(gsst->config.cpha){
		gsst->delay();
		gsst->clk_set(!gsst->config.cpol);
	}

	for (i = 0; i < gsst->bpt; i++) {
		//send edge to notify the slave to prepare data
		gsst->clk_set((gsst->config.cpol == gsst->config.cpha)?0:1);

		//prepare data for slave
		if(gsst->config.lsb_msb){
			bit = ((send_data&(mark>>i)) == 0 ? 0:1);
		}
		else{
			bit = ((send_data&(mark<<i)) == 0 ? 0:1);
		}
		if(gsst->dat_set != 0){
			gsst->dat_set(bit);
		}

		//give some time to make sure the slave prepare data finish
		gsst->delay();

		//send edge to notify the slave device to lock/read the data of master
		gsst->clk_set((gsst->config.cpol == gsst->config.cpha)?1:0);

		//slave prepare data should be finish, lock/read the data of slave
		if(gsst->dat_get != 0){
			bit = gsst->dat_get();
			if(bit){
				if(gsst->config.lsb_msb){
					rec |= (mark>>i);
				}
				else{
					rec |= (mark<<i);
				}
			}
		}

		//give some time to make sure the slave lock/read data success
		gsst->delay();
	}

	//clock idle state
	gsst->clk_set(gsst->config.cpol);

	return rec;
}

U32 gsst_transmit_slave(GSST_STRUCT* gsst, U32 send_data)
{
	U8 i;
	U8 bit;
	U32 mark;
	U32 rec = 0;

	if(gsst->config.mst_slv != 1){
		return 0;
	}
	if(gsst->bpt > 32){
		return 0;
	}
	if(gsst->clk_get == 0){
		return 0;
	}

	if(gsst->config.lsb_msb){
		mark = 1<<(gsst->bpt-1);
	}
	else{
		mark = 1;
	}

	//wait the clock idle state
	while(gsst->clk_get() != gsst->config.cpol);
	//CPHA = 1, wait the leading edge
	if(gsst->config.cpha){
		while(gsst->clk_get() != !gsst->config.cpol);
	}

	for (i = 0; i < gsst->bpt; i++) {
		//wait edge of prepare data
		while(gsst->clk_get() != ((gsst->config.cpol == gsst->config.cpha)?0:1));

		// prepare data for master
		if(gsst->config.lsb_msb){
			bit = ((send_data&(mark>>i)) == 0 ? 0:1);
		}
		else{
			bit = ((send_data&(mark<<i)) == 0 ? 0:1);
		}
		if(gsst->dat_set != 0){
			gsst->dat_set(bit);
		}

		//wait the edge to lock/read the data of master
		while(gsst->clk_get() != ((gsst->config.cpol == gsst->config.cpha)?1:0));

		//lock/read the data of master
		if(gsst->dat_get != 0){
			bit = gsst->dat_get();
			if(bit){
				if(gsst->config.lsb_msb){
					rec |= (mark>>i);
				}
				else{
					rec |= (mark<<i);
				}
			}
		}
	}

	return rec;
}

